<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>Java并发编程4（JUC篇） | XuanCode</title><meta name="author" content="xuanskeys"><meta name="copyright" content="xuanskeys"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="本篇文章重点介绍JUC（java.util.concurrent）  JUC是”java.util.concurrent”包的简称，它是Java提供的一个并发工具包，旨在简化多线程编程，提供了丰富的类和接口来帮助开发者更高效、更安全地编写并发程序。JUC包增强了Java对并发的支持，解决了传统多线程编程中的一些难题，如死锁、竞争条件和资源管理等。    原子变量  基本类型原子变量 AtomicI">
<meta property="og:type" content="article">
<meta property="og:title" content="Java并发编程4（JUC篇）">
<meta property="og:url" content="http://xuanskeys.github.io/2025/04/20/JUC4/index.html">
<meta property="og:site_name" content="XuanCode">
<meta property="og:description" content="本篇文章重点介绍JUC（java.util.concurrent）  JUC是”java.util.concurrent”包的简称，它是Java提供的一个并发工具包，旨在简化多线程编程，提供了丰富的类和接口来帮助开发者更高效、更安全地编写并发程序。JUC包增强了Java对并发的支持，解决了传统多线程编程中的一些难题，如死锁、竞争条件和资源管理等。    原子变量  基本类型原子变量 AtomicI">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://xuanskeys.github.io/image/person.jpg">
<meta property="article:published_time" content="2025-04-20T02:01:01.000Z">
<meta property="article:modified_time" content="2025-04-20T02:02:40.994Z">
<meta property="article:author" content="xuanskeys">
<meta property="article:tag" content="1">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://xuanskeys.github.io/image/person.jpg"><script type="application/ld+json">{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Java并发编程4（JUC篇）",
  "url": "http://xuanskeys.github.io/2025/04/20/JUC4/",
  "image": "http://xuanskeys.github.io/image/person.jpg",
  "datePublished": "2025-04-20T02:01:01.000Z",
  "dateModified": "2025-04-20T02:02:40.994Z",
  "author": [
    {
      "@type": "Person",
      "name": "xuanskeys",
      "url": "http://xuanskeys.github.io/"
    }
  ]
}</script><link rel="shortcut icon" href="/image/%E5%AF%BF%E5%8F%B8.png"><link rel="canonical" href="http://xuanskeys.github.io/2025/04/20/JUC4/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css"><script>
    (() => {
      
    const saveToLocal = {
      set: (key, value, ttl) => {
        if (!ttl) return
        const expiry = Date.now() + ttl * 86400000
        localStorage.setItem(key, JSON.stringify({ value, expiry }))
      },
      get: key => {
        const itemStr = localStorage.getItem(key)
        if (!itemStr) return undefined
        const { value, expiry } = JSON.parse(itemStr)
        if (Date.now() > expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return value
      }
    }

    window.btf = {
      saveToLocal,
      getScript: (url, attr = {}) => new Promise((resolve, reject) => {
        const script = document.createElement('script')
        script.src = url
        script.async = true
        Object.entries(attr).forEach(([key, val]) => script.setAttribute(key, val))
        script.onload = script.onreadystatechange = () => {
          if (!script.readyState || /loaded|complete/.test(script.readyState)) resolve()
        }
        script.onerror = reject
        document.head.appendChild(script)
      }),
      getCSS: (url, id) => new Promise((resolve, reject) => {
        const link = document.createElement('link')
        link.rel = 'stylesheet'
        link.href = url
        if (id) link.id = id
        link.onload = link.onreadystatechange = () => {
          if (!link.readyState || /loaded|complete/.test(link.readyState)) resolve()
        }
        link.onerror = reject
        document.head.appendChild(link)
      }),
      addGlobalFn: (key, fn, name = false, parent = window) => {
        if (!false && key.startsWith('pjax')) return
        const globalFn = parent.globalFn || {}
        globalFn[key] = globalFn[key] || {}
        globalFn[key][name || Object.keys(globalFn[key]).length] = fn
        parent.globalFn = globalFn
      }
    }
  
      
      const activateDarkMode = () => {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      const activateLightMode = () => {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }

      btf.activateDarkMode = activateDarkMode
      btf.activateLightMode = activateLightMode

      const theme = saveToLocal.get('theme')
    
          theme === 'dark' ? activateDarkMode() : theme === 'light' ? activateLightMode() : null
        
      
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        document.documentElement.classList.toggle('hide-aside', asideStatus === 'hide')
      }
    
      
    const detectApple = () => {
      if (/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)) {
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
  
    })()
  </script><script>const GLOBAL_CONFIG = {
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"未找到符合您查询的内容：${query}","hits_stats":"共找到 ${hits} 篇文章"}},
  translate: undefined,
  highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false,"highlightFullpage":false,"highlightMacStyle":false},
  copy: {
    success: '复制成功',
    error: '复制失败',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  dateSuffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'null',
  Snackbar: undefined,
  infinitegrid: {
    js: 'https://cdn.jsdelivr.net/npm/@egjs/infinitegrid/dist/infinitegrid.min.js',
    buttonText: '加载更多'
  },
  isPhotoFigcaption: false,
  islazyloadPlugin: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: false,
  },
  autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Java并发编程4（JUC篇）',
  isHighlightShrink: false,
  isToc: true,
  pageType: 'post'
}</script><link rel="stylesheet" href="/styles/main.css"><script src="/styles/fish.js"></script><script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script><meta name="generator" content="Hexo 7.3.0"></head><body><div id="loading-box"><div class="loading-left-bg"></div><div class="loading-right-bg"></div><div class="spinner-box"><div class="configure-border-1"><div class="configure-core"></div></div><div class="configure-border-2"><div class="configure-core"></div></div><div class="loading-word">加载中...</div></div></div><script>(()=>{
  const $loadingBox = document.getElementById('loading-box')
  const $body = document.body
  const preloader = {
    endLoading: () => {
      $body.style.overflow = ''
      $loadingBox.classList.add('loaded')
    },
    initLoading: () => {
      $body.style.overflow = 'hidden'
      $loadingBox.classList.remove('loaded')
    }
  }

  preloader.initLoading()
  window.addEventListener('load', preloader.endLoading)

  if (false) {
    btf.addGlobalFn('pjaxSend', preloader.initLoading, 'preloader_init')
    btf.addGlobalFn('pjaxComplete', preloader.endLoading, 'preloader_end')
  }
})()</script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img text-center"><img src="/image/person.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data text-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">10</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">1</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">5</div></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><span class="site-page group"><i class="fa-fw fa fa-heartbeat"></i><span> 清单</span><i class="fas fa-chevron-down"></i></span><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/Gallery/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url(/image/background.jpg);"><nav id="nav"><span id="blog-info"><a class="nav-site-title" href="/"><span class="site-name">XuanCode</span></a><a class="nav-page-title" href="/"><span class="site-name">Java并发编程4（JUC篇）</span></a></span><div id="menus"><div id="search-button"><span class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></span></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><span class="site-page group"><i class="fa-fw fa fa-heartbeat"></i><span> 清单</span><i class="fas fa-chevron-down"></i></span><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/Gallery/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div></div><div id="toggle-menu"><span class="site-page"><i class="fas fa-bars fa-fw"></i></span></div></div></nav><div id="post-info"><h1 class="post-title">Java并发编程4（JUC篇）</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2025-04-20T02:01:01.000Z" title="发表于 2025-04-20 10:01:01">2025-04-20</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2025-04-20T02:02:40.994Z" title="更新于 2025-04-20 10:02:40">2025-04-20</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/">Java并发编程</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title=""><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">浏览量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="container post-content" id="article-container"><p>本篇文章重点介绍JUC（java.util.concurrent）</p>
<blockquote>
<p>JUC是”java.util.concurrent”包的简称，它是Java提供的一个并发工具包，旨在简化多线程编程，提供了丰富的类和接口来帮助开发者更高效、更安全地编写并发程序。JUC包增强了Java对并发的支持，解决了传统多线程编程中的一些难题，如死锁、竞争条件和资源管理等。</p>
</blockquote>
<p><img src="/./../images/724cf2c283f5497fa5c3ea2f214defce.png" alt="img"><img src="" alt="点击并拖拽以移动"> </p>
<h1><span id="原子变量">原子变量</span></h1><h2><span id="基本类型原子变量"><img src="/./../images/0bd58f04fc6144f484a107320868af9a.png" alt="img"><img src="" alt="点击并拖拽以移动">  基本类型原子变量</span></h2><blockquote>
<p>AtomicInteger</p>
<ul>
<li>提供对整型值的原子操作，如加法、减法等。</li>
<li>方法示例：incrementAndGet(), decrementAndGet(), addAndGet(int delta), compareAndSet(int expect, int update)。</li>
</ul>
<p>AtomicLong</p>
<ul>
<li>类似于AtomicInteger，但是针对长整型（long）值。</li>
<li>方法与AtomicInteger相似，适用于需要处理较大数值的情况。</li>
</ul>
<p>AtomicBoolean</p>
<ul>
<li>支持布尔类型的原子操作。</li>
<li>方法示例：get(), set(boolean newValue), compareAndSet(boolean expect, boolean update)。</li>
</ul>
</blockquote>
<h2><span id="对象引用原子变量">对象引用原子变量</span></h2><blockquote>
<p>AtomicReference<v></v></p>
<ul>
<li>用于对象引用的原子更新。</li>
<li>方法示例：get(), set(V newValue), compareAndSet(V expect, V update)。</li>
</ul>
<p>AtomicStampedReference<v></v></p>
<ul>
<li>带版本号的对象引用原子变量，解决ABA问题。</li>
<li>方法示例：get(), set(V newValue, int newStamp), compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)。</li>
</ul>
<p>AtomicMarkableReference<v></v></p>
<ul>
<li>带标记位的对象引用原子变量，适用于需要记录是否发生过变化的情况。</li>
<li>方法示例：getReference(), isMarked(), compareAndSet(V expectedReference, V newReference, boolean expectedMark, boolean newMark)。</li>
</ul>
</blockquote>
<h2><span id="数组类型的原子变量">数组类型的原子变量</span></h2><blockquote>
<p>AtomicIntegerArray</p>
<ul>
<li>提供对整型数组元素的原子操作。</li>
<li>方法示例：get(int i), set(int i, int newValue), incrementAndGet(int i), compareAndSet(int i, int expect, int update)。</li>
</ul>
<p>AtomicLongArray</p>
<ul>
<li>类似于AtomicIntegerArray，但针对长整型数组。</li>
<li>方法与AtomicIntegerArray相似。</li>
</ul>
<p>AtomicReferenceArray<v></v></p>
<ul>
<li>提供对对象引用数组元素的原子操作。</li>
<li>方法示例：get(int i), set(int i, V newValue), compareAndSet(int i, V expect, V update)。</li>
</ul>
</blockquote>
<h2><span id="字段更新器">字段更新器</span></h2><blockquote>
<p>AtomicIntegerFieldUpdater<t></t></p>
<ul>
<li>提供对现有对象字段进行原子更新的能力，无需直接使用原子变量。</li>
<li>使用时需注意字段必须是volatile类型，并且不能是private。</li>
</ul>
<p>AtomicLongFieldUpdater<t></t></p>
<ul>
<li>类似于AtomicIntegerFieldUpdater，但适用于长整型字段。</li>
</ul>
<p>AtomicReferenceFieldUpdater&lt;T, V&gt;</p>
<ul>
<li>提供对对象引用字段的原子更新能力。</li>
</ul>
</blockquote>
<h2><span id="atomicstampedreference">AtomicStampedReference<v></v></span></h2><h3><span id="介绍">介绍：</span></h3><p>解决了ABA问题的一种原子引用实现，通过引入版本号（称为“邮票”）来区分即使是相同的对象引用也可能是不同的状态。</p>
<p>典型应用场景：解决复杂的并发控制问题，特别是在可能出现ABA问题的场合。<br> 常用方法：getReference() 和 getStamp() 获取引用及其版本号；compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) 进行带有版本检查的更新。</p>
<h3><span id="aba问题的描述">ABA问题的描述</span></h3><p>假设有一个共享变量A，其初始值为A。现在有两个线程Thread 1和Thread 2同时操作这个变量：</p>
<ul>
<li>Thread 1读取变量的值A。</li>
<li>在Thread 1执行其他操作期间，Thread 2首先将变量的值从A改为B，然后又改回A。</li>
<li>当Thread 1尝试使用类似compareAndSet(A, newValue)的操作来更新变量时，它会发现当前变量的值仍然是A，因此认为在这段时间内没有其他线程修改过该变量，并继续执行更新操作。</li>
<li>但实际上，在这段时间里，变量已经经历了从A到B再到A的变化过程，这可能导致程序逻辑上的错误或数据不一致的情况。</li>
</ul>
<h3><span id="aba问题的具体场景">ABA问题的具体场景</span></h3><p>设想有三个线程：Thread 1、Thread 2 和 Thread 3，以及初始栈结构如下：</p>
<p>栈顶 -&gt; A(10) -&gt; B(20) -&gt; null</p>
<p>现在考虑以下执行顺序：</p>
<p><strong>1.Thread 1 开始执行pop()操作：</strong></p>
<ul>
<li>它读取到当前栈顶为A(10)。</li>
<li>在获取A.next之前被抢占。</li>
</ul>
<p><strong>2.Thread 2 执行两次pop()操作</strong></p>
<ul>
<li>弹出了A(10)和B(20)，然后又压入了C(30)和A(10)，使得栈变为：栈顶 -&gt; A(10) -&gt; C(30) -&gt; null</li>
</ul>
<p><strong>3.Thread 1 恢复执行：</strong></p>
<ul>
<li>它继续执行，发现A.next指向的是B(20)（这是它最初看到的状态），但实际上现在的A.next指向的是C(30)。</li>
<li>当它尝试使用CAS将栈顶从A(10)改为B(20)时，由于此时栈顶确实是A(10)，CAS操作成功。</li>
<li>结果是，栈变成了B(20) -&gt; C(30) -&gt; null，而实际上应该保持为A(10) -&gt; C(30) -&gt; null。</li>
</ul>
<h3><span id="源码分析">源码分析</span></h3><h4><span id="构造方法">构造方法</span></h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 初始化一个带有时间戳的原子引用对象</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> initialRef 初始引用对象，表示要被引用的对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> initialStamp 初始时间戳，用于检测和防止虚假冲突</span></span><br><span class="line"><span class="comment"> * </span></span><br><span class="line"><span class="comment"> * 使用Pair.of方法来创建并初始化一个Pair对象，该Pair对象包含了引用对象和时间戳</span></span><br><span class="line"><span class="comment"> * 这个构造方法允许用户在创建AtomicStampedReference对象时指定初始的引用对象和时间戳</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="title function_">AtomicStampedReference</span><span class="params">(V initialRef, <span class="type">int</span> initialStamp)</span> &#123;</span><br><span class="line">    pair = Pair.of(initialRef, initialStamp);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="" alt="点击并拖拽以移动"></p>
<p>这个pair通过volitaile修饰的</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 一个泛型类，用于存储一个引用及其关联的版本戳。</span></span><br><span class="line"><span class="comment"> * 主要用途是封装对实际对象的引用和一个表示版本的整数，</span></span><br><span class="line"><span class="comment"> * 允许程序通过比较版本戳来确定引用是否被修改。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &lt;T&gt; 引用的类型，表示该类可以用于任何对象类型。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">Pair</span>&lt;T&gt; &#123;</span><br><span class="line">    <span class="keyword">final</span> T reference; <span class="comment">// 存储的引用对象</span></span><br><span class="line">    <span class="keyword">final</span> <span class="type">int</span> stamp;   <span class="comment">// 关联的版本戳</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 构造函数，用于创建 Pair 对象。</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> reference 要存储的对象引用。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> stamp 关联的版本戳，用于表示对象的状态或版本。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">Pair</span><span class="params">(T reference, <span class="type">int</span> stamp)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.reference = reference;</span><br><span class="line">        <span class="built_in">this</span>.stamp = stamp;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 静态工厂方法，用于创建 Pair 对象。</span></span><br><span class="line"><span class="comment">     * 该方法提供了一种更灵活的方式来创建 Pair 对象，简化了实例化过程。</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> reference 要存储的对象引用。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> stamp 关联的版本戳。</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 返回一个包含给定引用和版本戳的 Pair 对象。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">static</span> &lt;T&gt; Pair&lt;T&gt; <span class="title function_">of</span><span class="params">(T reference, <span class="type">int</span> stamp)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Pair</span>&lt;T&gt;(reference, stamp);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 一个 volatile 的 Pair 对象，用于存储对象引用及其对应的版本戳。</span></span><br><span class="line"><span class="comment"> * 声明为 volatile 以确保多个线程可以安全地访问这个 Pair 对象，</span></span><br><span class="line"><span class="comment"> * 维护对该变量的写操作的可见性和顺序性。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">volatile</span> Pair&lt;V&gt; pair;</span><br></pre></td></tr></table></figure>

<p><img src="" alt="点击并拖拽以移动"></p>
<h4><span id="compareandset">compareAndSet</span></h4><blockquote>
<p>&#x2F;**<br> * 使用原子方式比较并设置引用和戳<br> * 此方法用于在当前引用和戳与预期值匹配时，将引用和戳更新为新值<br> * 它是实现非阻塞算法的关键，特别是在并发控制中<br> *<br> * @param expectedReference 预期的引用值<br> * @param newReference 新的引用值<br> * @param expectedStamp 预期的戳值<br> * @param newStamp 新的戳值<br> * @return 如果更新成功则返回true，否则返回false<br> *&#x2F;<br> public boolean compareAndSet(V  expectedReference,<br>                V  newReference,<br>                int expectedStamp,<br>                int newStamp) {<br>     &#x2F;&#x2F; 获取当前的引用和戳对<br>     Pair<v> current &#x3D; pair;<br>     &#x2F;&#x2F; 检查当前的引用和戳是否与预期值匹配<br>     &#x2F;&#x2F; 如果匹配，则进一步检查新值是否与当前值相同，或尝试使用CAS操作更新值<br>     return<br>       expectedReference &#x3D;&#x3D; current.reference &amp;&amp;<br>       expectedStamp &#x3D;&#x3D; current.stamp &amp;&amp;<br>       ((newReference &#x3D;&#x3D; current.reference &amp;&amp;<br>        newStamp &#x3D;&#x3D; current.stamp) ||<br>        casPair(current, Pair.of(newReference, newStamp)));<br>   }</v></p>
</blockquote>
<h4><span id="weakcompareandset">weakCompareAndSet</span></h4><blockquote>
<p> &#x2F;**<br> * 使用弱一致性比较并设置引用和戳<br> * 此方法与compareAndSet方法类似，但它使用弱一致性，这意味着在某些情况下，<br> * 它可能返回false，即使比较成功，这通常是为了提高性能<br> *<br> * @param expectedReference 预期的引用值<br> * @param newReference    新的引用值，如果预期引用匹配则设置此值<br> * @param expectedStamp   预期的戳值<br> * @param newStamp      新的戳值，如果预期戳匹配则设置此值<br> * @return 如果设置操作成功则返回true，否则返回false<br> *&#x2F;<br> public boolean weakCompareAndSet(V  expectedReference,<br>                  V  newReference,<br>                  int expectedStamp,<br>                  int newStamp) {<br>   return compareAndSet(expectedReference, newReference,<br>              expectedStamp, newStamp);<br> }</p>
</blockquote>
<h4><span id="attemptstamp">attemptStamp</span></h4><blockquote>
<p> &#x2F;**<br> * 尝试更新引用对象的版本号<br> * 此方法旨在更新引用对象的版本号（stamp），以实现更复杂的同步或版本控制逻辑<br> * 它首先检查当前引用对象是否与预期的引用对象匹配，然后尝试更新版本号如果版本号不匹配，<br> * 它会尝试使用CAS（Compare-And-Swap）操作来更新引用对象和版本号<br> *<br> * @param expectedReference 预期的引用对象，即我们期望当前引用对象所指向的对象<br> * @param newStamp 新的版本号，我们尝试更新引用对象到这个版本号<br> * @return 如果成功更新引用对象的版本号，则返回true；否则返回false<br> *&#x2F;<br> public boolean attemptStamp(V expectedReference, int newStamp) {<br>   &#x2F;&#x2F; 获取当前的引用对象和版本号对<br>   Pair<v> current &#x3D; pair;<br>   &#x2F;&#x2F; 检查预期的引用对象是否与当前引用对象匹配，并尝试更新版本号<br>   return<br>     expectedReference &#x3D;&#x3D; current.reference &amp;&amp;<br>     (newStamp &#x3D;&#x3D; current.stamp ||<br>      casPair(current, Pair.of(expectedReference, newStamp)));<br> }</v></p>
</blockquote>
<h4><span id="unsafe机制">Unsafe机制</span></h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Unsafe 机制</span></span><br><span class="line"><span class="comment">// 使用 sun.misc.Unsafe 进行低级别的操作，绕过 Java 语言的安全检查。</span></span><br><span class="line"><span class="comment">// 注意：sun.misc.Unsafe 的使用通常不被推荐，因为它可能导致稳定性与安全性问题，并且它不属于标准 Java API。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> sun.misc.<span class="type">Unsafe</span> <span class="variable">UNSAFE</span> <span class="operator">=</span> sun.misc.Unsafe.getUnsafe();</span><br><span class="line"><span class="comment">// 获取 AtomicStampedReference 中 &quot;pair&quot; 字段的内存偏移量</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">pairOffset</span> <span class="operator">=</span></span><br><span class="line">    objectFieldOffset(UNSAFE, <span class="string">&quot;pair&quot;</span>, AtomicStampedReference.class);</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 尝试原子地更新当前实例的 pair 字段。</span></span><br><span class="line"><span class="comment"> * 该方法使用 Unsafe 执行比较并交换（CAS）操作，这是实现无锁算法的关键部分。</span></span><br><span class="line"><span class="comment"> * 它通过确保更新是原子的来保证线程安全：仅当当前值与预期值相同时，更新才会成功。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> cmp 预期的旧值</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> val 要设置的新值</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 如果更新成功则返回 true，否则返回 false</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">casPair</span><span class="params">(Pair&lt;V&gt; cmp, Pair&lt;V&gt; val)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> UNSAFE.compareAndSwapObject(<span class="built_in">this</span>, pairOffset, cmp, val);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取指定类中指定字段的内存偏移量。</span></span><br><span class="line"><span class="comment"> * 该方法通过查找字段的确切位置，为低级别操作做准备。</span></span><br><span class="line"><span class="comment"> * 它是一个辅助函数，简化了获取字段偏移量的过程。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> UNSAFE 用于低级别操作的 Unsafe 实例</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> field 目标字段的名称</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> klazz 包含目标字段的类</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> 字段的内存偏移量</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> NoSuchFieldError 如果找不到指定字段，则抛出此错误</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="type">long</span> <span class="title function_">objectFieldOffset</span><span class="params">(sun.misc.Unsafe UNSAFE,</span></span><br><span class="line"><span class="params">                              String field, Class&lt;?&gt; klazz)</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (NoSuchFieldException e) &#123;</span><br><span class="line">        <span class="comment">// 将异常转换为对应的错误</span></span><br><span class="line">        <span class="type">NoSuchFieldError</span> <span class="variable">error</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">NoSuchFieldError</span>(field);</span><br><span class="line">        error.initCause(e);</span><br><span class="line">        <span class="keyword">throw</span> error;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="" alt="点击并拖拽以移动"></p>
<h1><span id="并发集合">并发集合</span></h1><h2><span id="集合">集合</span></h2><blockquote>
<p><strong>ConcurrentHashMap</strong></p>
<ul>
<li>线程安全的哈希表实现，支持高并发读写操作。</li>
</ul>
<p><strong>CopyOnWriteArrayList</strong></p>
<ul>
<li>线程安全的列表，适用于读多写少的场景，写操作时创建底层数组的新副本。</li>
</ul>
<p><strong>CopyOnWriteArraySet</strong></p>
<ul>
<li>基于CopyOnWriteArrayList实现的线程安全集合，保证元素唯一性。</li>
</ul>
<p><strong>ConcurrentLinkedQueue</strong></p>
<ul>
<li>无界线程安全队列，基于链表结构，支持高效的插入和移除操作。</li>
</ul>
<p><strong>ConcurrentLinkedDeque</strong></p>
<ul>
<li>类似于ConcurrentLinkedQueue，但支持双端队列操作。</li>
</ul>
<p><strong>BlockingQueue接口及其实现类</strong></p>
<ul>
<li>ArrayBlockingQueue：有界的阻塞队列。</li>
<li>LinkedBlockingQueue：可选容量限制的阻塞队列。</li>
<li>PriorityBlockingQueue：支持优先级排序的无界阻塞队列。</li>
<li>DelayQueue：元素只有在延迟期满后才能从队列中取出。</li>
<li>SynchronousQueue：不存储元素的阻塞队列，每个插入操作必须等待相应的删除操作，反之亦然。</li>
<li>LinkedTransferQueue：实现了TransferQueue接口的无界阻塞队列。</li>
</ul>
<p><strong>ConcurrentSkipListMap</strong></p>
<ul>
<li>线程安全的可排序映射，基于跳表数据结构，允许范围查询。</li>
</ul>
<p><strong>ConcurrentSkipListSet</strong></p>
<ul>
<li>基于ConcurrentSkipListMap实现的线程安全集合，支持排序。</li>
</ul>
<p><strong>ConcurrentHashMap.KeySetView</strong></p>
<ul>
<li>ConcurrentHashMap的键视图，提供了一种方式来使用ConcurrentHashMap作为集合。</li>
</ul>
</blockquote>
<h2><span id="concurrenthashmap">ConcurrentHashMap</span></h2><blockquote>
<p>ConcurrentHashMap 是 Java 中 java.util.concurrent 包提供的一个高效且线程安全的哈希表实现。它在多线程环境下提供了比传统的同步集合（如 Collections.synchronizedMap() 或者 Hashtable）更好的并发性能，同时避免了传统锁机制带来的瓶颈问题</p>
</blockquote>
<h3><span id="特点">特点</span></h3><blockquote>
<p><strong>1.分段锁机制（Segment Locking）</strong></p>
<ul>
<li>在早期版本（Java 7及之前），ConcurrentHashMap 使用了一种称为“分段锁”的技术来减少锁竞争。整个哈希表被划分为多个段（segments），每个段实际上是一个小的哈希表，拥有自己的锁。这样，在理想情况下，不同的线程可以同时访问不同段的数据而不会发生冲突。</li>
<li>从Java 8开始，这种设计被替换为更细粒度的锁机制——CAS（Compare-And-Swap）操作结合同步标记（synchronized blocks），这使得大部分读写操作可以在不加锁的情况下完成，进一步提高了并发性能。</li>
</ul>
<p><strong>2.无阻塞读取</strong></p>
<ul>
<li>ConcurrentHashMap 支持完全并发的读操作，即使有其他线程正在进行写操作或结构化修改（如增加&#x2F;删除节点）。这是因为它的内部结构允许在不锁定整个表的情况下进行读取。</li>
<li>高效的扩容机制</li>
<li>当哈希表需要扩容时，ConcurrentHashMap 并不是一次性锁定整个表来进行复制和迁移工作，而是将这个过程分散到多次增量更新中完成，从而减少了对系统性能的影响。</li>
</ul>
<p><strong>3.弱一致性迭代器</strong></p>
<ul>
<li>迭代器不会抛出 ConcurrentModificationException，并且它们是弱一致性的：它们反映的是某个时间点上的快照，并可能包含已删除的元素，但绝不会返回从未添加过的元素。</li>
</ul>
<p><strong>4.支持原子操作的方法</strong></p>
<ul>
<li>提供了一系列支持原子操作的方法，如 putIfAbsent, remove(Object key, Object value), replace(K key, V oldValue, V newValue) 等，这些方法可以帮助开发者编写更加简洁和高效的代码。</li>
</ul>
</blockquote>
<h3><span id="扩容机制">扩容机制</span></h3><h4><span id="触发条件">触发条件：</span></h4><p>扩容通常发生在插入新键值对时，如果当前哈希表的负载因子（即元素数量与桶数组长度的比例）超过了预定阈值。具体来说，当ConcurrentHashMap中的元素数量超过了容量乘以负载因子(loadFactor)时，就会触发扩容操作。默认情况下，负载因子设置为0.75。</p>
<h4><span id="扩容过程">扩容过程</span></h4><blockquote>
<p><strong>1.创建新数组：</strong></p>
<ul>
<li>首先确定需要扩容后的新容量（通常是原容量的两倍），然后创建一个新的桶数组。</li>
</ul>
<p><strong>2.迁移数据：</strong></p>
<ul>
<li>对于旧数组中的每个非空桶（包括链表或红黑树结构），需要将其重新分配到新数组中。由于新数组的大小是原来的两倍，所以每个桶的数据可能被分配到新数组中的两个位置之一。</li>
<li>具体来说，对于一个位于索引i的桶，在新数组中它可能会被放置在i或i + oldCapacity的位置上（其中oldCapacity是旧数组的容量）。</li>
</ul>
<p><strong>3.并行迁移：</strong></p>
<ul>
<li>不同于一次性完成所有数据的迁移，ConcurrentHashMap采用了一种增量迁移的方式。这意味着不是由单个线程负责整个迁移过程，而是任何访问到未迁移桶的线程都可以帮助完成这部分桶的迁移工作。</li>
<li>这种设计允许多个线程同时参与扩容过程，从而加速了迁移速度，并减少了对系统性能的影响。</li>
</ul>
<p><strong>4.完成扩容：</strong></p>
<ul>
<li>当所有的桶都成功迁移到新的数组中后，旧的数组将被废弃，新的数组成为ConcurrentHashMap的实际存储结构。</li>
<li>在此过程中，ConcurrentHashMap仍然能够处理查询、插入等操作，保证了系统的高可用性。</li>
</ul>
</blockquote>
<h1><span id="executor框架">Executor框架</span></h1><h2><span id="executor框架主要组成">Executor框架主要组成</span></h2><blockquote>
<p><strong>Executor接口：</strong></p>
<ul>
<li>这是最基础的接口，只有一个方法void execute(Runnable command);。它代表一个对象，其职责是执行提交给它的Runnable任务。</li>
</ul>
<p><strong>ExecutorService接口：</strong></p>
<ul>
<li>继承自Executor接口，增加了管理服务的功能，如终止现有任务、等待所有已提交任务完成等。提供了更丰富的控制能力，比如提交带返回值的任务(Callable)、批量提交任务等。</li>
</ul>
<p><strong>AbstractExecutorService类：</strong></p>
<ul>
<li>为ExecutorService接口提供了一个默认的实现模板，方便开发者创建自定义的执行服务。</li>
</ul>
<p><strong>ScheduledExecutorService接口：</strong></p>
<ul>
<li>继承自ExecutorService接口，支持延迟和周期性任务的执行。</li>
</ul>
<p><strong>Executors工厂类：</strong>提供了静态方法用于创建不同类型的线程池，包括但不限于：</p>
<ul>
<li>newFixedThreadPool(int nThreads)：创建一个固定大小的线程池。</li>
<li>newCachedThreadPool()：创建一个可根据需要创建新线程的线程池。</li>
<li>newSingleThreadExecutor()：创建一个单线程的线程池。</li>
<li>newScheduledThreadPool(int corePoolSize)：创建一个支持定时及周期性任务执行的线程池。</li>
</ul>
</blockquote>
<h2><span id="线程池">线程池</span></h2><h3><span id="概念">概念</span></h3><p>线程池是一种用于管理和复用一组线程的技术，它避免了频繁创建和销毁线程所带来的开销。通过预先创建一定数量的线程并将其保持在一个池中，可以显著提升应用程序的性能。</p>
<h3><span id="线程池的创建">线程池的创建</span></h3><p>在JUC中，可以通过多种方式创建线程池，最常用的方式是使用Executors工厂类提供的静态方法，如：</p>
<ul>
<li>newFixedThreadPool(int nThreads)：创建一个固定大小的线程池。</li>
<li>newCachedThreadPool()：创建一个根据需要创建新线程的线程池，但在以前构造的线程可用时将重用它们。</li>
<li>newSingleThreadExecutor()：创建一个单线程的线程池。</li>
<li>newScheduledThreadPool(int corePoolSize)：创建一个支持定时及周期性任务执行的线程池。</li>
</ul>
<p>当然，也可以直接使用ThreadPoolExecutor或ScheduledThreadPoolExecutor来更灵活地配置线程池参数。</p>
<h3><span id="线程池工作流程">线程池工作流程</span></h3><blockquote>
<p><strong>1.任务提交：</strong></p>
<ul>
<li>当你向线程池提交一个新的任务（通过调用execute(Runnable command)方法），该任务会被放入队列等待执行。</li>
</ul>
<p><strong>2.任务分配：</strong></p>
<ul>
<li>如果当前运行的线程少于核心线程数（corePoolSize），则创建新的线程来处理任务。</li>
<li>如果当前运行的线程数等于或大于核心线程数，则将任务加入到任务队列等待空闲线程处理。</li>
<li>如果任务队列已满，并且当前运行的线程数小于最大线程数（maximumPoolSize），则会创建新的线程来处理任务。</li>
<li>如果线程数已经达到了最大线程数并且任务队列也满了，则根据拒绝策略处理无法执行的任务。</li>
</ul>
<p><strong>3.任务执行：</strong>线程从任务队列中取出任务并执行。<br> <strong>4.线程回收：</strong></p>
<ul>
<li>当线程完成任务后，如果此时线程池中的线程数超过了核心线程数，并且这些多余的线程在一段时间内（keepAliveTime）没有新的任务可执行，则这些线程将会被终止以节省资源。</li>
</ul>
<p><strong>5.拒绝策略：</strong></p>
<p>当线程池无法接受新的任务时，会按照预设的拒绝策略进行处理。JUC提供了几种默认的拒绝策略，如：</p>
<ul>
<li>AbortPolicy：抛出RejectedExecutionException异常。</li>
<li>CallerRunsPolicy：由提交任务的线程自己运行该任务。</li>
<li>DiscardPolicy：直接丢弃任务，不抛出异常。</li>
<li>DiscardOldestPolicy：丢弃队列中最老的任务，然后尝试重新提交此任务。</li>
</ul>
</blockquote>
<h2><span id></span></h2><h1><span id="threadpoolexecutor">ThreadPoolExecutor</span></h1><h2><span id="案例引入">案例引入：</span></h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个ThreadPoolExecutor线程池</span></span><br><span class="line"> <span class="comment">// 核心线程数为2，最大线程数为5</span></span><br><span class="line"> <span class="comment">// 空闲线程存活时间为1秒</span></span><br><span class="line"> <span class="comment">// 使用ArrayBlockingQueue作为任务队列，容量为3</span></span><br><span class="line"> <span class="comment">// 当任务队列已满且线程数达到最大时，使用丢弃策略处理无法执行的任务</span></span><br><span class="line"> <span class="type">ThreadPoolExecutor</span> <span class="variable">executor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(</span><br><span class="line">         <span class="number">2</span>, <span class="number">3</span>, <span class="number">1</span>, TimeUnit.SECONDS, <span class="keyword">new</span> <span class="title class_">ArrayBlockingQueue</span>&lt;&gt;(<span class="number">3</span>),</span><br><span class="line">         <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>.DiscardPolicy()</span><br><span class="line"> );</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">10</span>; i ++) &#123;</span><br><span class="line">     <span class="type">int</span> <span class="variable">finalI</span> <span class="operator">=</span> i;</span><br><span class="line">     <span class="type">Runnable</span> <span class="variable">task</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Runnable</span>() &#123;</span><br><span class="line">         <span class="meta">@Override</span></span><br><span class="line">         <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">run</span><span class="params">()</span> &#123;</span><br><span class="line">             log.debug(<span class="string">&quot;running... task&#123;&#125;&quot;</span>, finalI);</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;;</span><br><span class="line">     executor.submit(task);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> System.out.println(executor.getTaskCount());</span><br><span class="line"> executor.shutdown();</span><br></pre></td></tr></table></figure>

<p><img src="" alt="点击并拖拽以移动"></p>
<p><img src="/./../images/9d6be143bc374fcd8dba9afa3027a5ff.png" alt="img"><img src="" alt="点击并拖拽以移动"> </p>
<h2><span id="参数说明">参数说明：</span></h2><p><img src="/./../images/9c838558c936494280009beafa6e5878.png" alt="img"><img src="" alt="点击并拖拽以移动"> </p>
<blockquote>
<p><strong>1. corePoolSize（核心线程数）</strong></p>
<ul>
<li>表示线程池中保持的最小线程数量。</li>
<li>即使这些线程处于空闲状态，也不会被销毁（除非设置了 allowCoreThreadTimeOut(true)）。</li>
<li>当提交任务时，如果当前运行的线程数小于 corePoolSize，即使有空闲线程，也会创建新线程来执行任务。</li>
</ul>
<p><strong>2. maximumPoolSize（最大线程数）</strong></p>
<ul>
<li>线程池中允许的最大线程数量。</li>
<li>当任务队列已满，并且当前运行的线程数小于 maximumPoolSize 时，线程池会创建新的线程来处理任务，直到达到 maximumPoolSize。</li>
<li>如果线程数已经达到 maximumPoolSize，并且任务队列也满了，则根据拒绝策略处理无法执行的任务。</li>
</ul>
<p><strong>3. keepAliveTime（空闲线程存活时间）</strong></p>
<ul>
<li>表示当线程池中的线程数超过 corePoolSize 时，多余空闲线程在终止前等待新任务的最长时间。</li>
<li>时间单位由 unit 参数指定。</li>
<li>默认情况下，keepAliveTime 只会影响超出核心线程数的线程；但可以通过调用 allowCoreThreadTimeOut(true) 方法，使得核心线程也遵循这个规则。</li>
</ul>
<p><strong>4. unit（时间单位）</strong><br> keepAliveTime 的时间单位。<br> 常见的时间单位包括：</p>
<ul>
<li>TimeUnit.NANOSECONDS：纳秒</li>
<li>TimeUnit.MICROSECONDS：微秒</li>
<li>TimeUnit.MILLISECONDS：毫秒</li>
<li>TimeUnit.SECONDS：秒</li>
<li>TimeUnit.MINUTES：分钟</li>
<li>TimeUnit.HOURS：小时</li>
<li>TimeUnit.DAYS：天</li>
</ul>
<p><strong>5. workQueue（任务队列）</strong><br> 用于保存等待执行的任务的阻塞队列。<br> 常见的任务队列类型：</p>
<ul>
<li>ArrayBlockingQueue：基于数组的有界阻塞队列。</li>
<li>LinkedBlockingQueue：基于链表的无界阻塞队列（默认容量为 Integer.MAX_VALUE）。</li>
<li>SynchronousQueue：不存储元素的队列，每个插入操作必须等待另一个线程的对应移除操作。</li>
<li>PriorityBlockingQueue：支持优先级排序的无界阻塞队列。</li>
</ul>
<p>队列的选择直接影响线程池的工作机制，例如任务排队和线程创建的策略。<br> <strong>6. threadFactory（线程工厂）</strong></p>
<ul>
<li>用于创建新线程的工厂。</li>
<li>默认使用 Executors.defaultThreadFactory()，它创建的线程具有相同的优先级（NORM_PRIORITY）并设置为非守护线程。</li>
<li>自定义线程工厂可以用来设置线程的名称、优先级、是否为守护线程等。</li>
</ul>
<p><strong>7. handler（拒绝策略）</strong><br> 当线程池和任务队列都满了时使用的处理策略。<br> 常见的拒绝策略：</p>
<ul>
<li>AbortPolicy：抛出 RejectedExecutionException 异常（默认策略）。</li>
<li>CallerRunsPolicy：由提交任务的线程自己执行该任务。</li>
<li>DiscardPolicy：直接丢弃任务，不做任何处理。</li>
<li>DiscardOldestPolicy：丢弃队列中最老的任务，然后尝试重新提交被拒绝的任务。</li>
</ul>
<p>也可以自定义拒绝策略，只需要实现 RejectedExecutionHandler 接口。</p>
</blockquote>
<h2><span id="1-提交任务">1. 提交任务</span></h2><ul>
<li><strong>execute(Runnable command)：</strong>用于执行不需要返回结果的任务（即实现了 Runnable 接口的任务）。该方法没有返回值。</li>
<li><strong>submit(Runnable task)：</strong>提交一个不需要返回结果的任务，并返回一个 Future 对象，可以通过这个对象来管理任务的状态或尝试取消任务。</li>
<li><strong>submit(Runnable task, T result)：</strong>类似于 submit(Runnable task)，但允许指定一个结果对象，在任务完成时可以获取到这个结果（虽然对于 Runnable 任务，这个结果通常是 null）。</li>
<li><strong>submit(Callable<t> task)：</t></strong>提交一个需要返回结果的任务（即实现了 Callable 接口的任务），并返回一个 Future 对象，通过这个对象可以获取任务执行的结果。</li>
</ul>
<h2><span id="2-线程池管理">2. 线程池管理</span></h2><ul>
<li><strong>shutdown()：</strong>启动一次顺序关闭，在这个方法调用之后，线程池不再接受新的任务，但是会继续执行已经在队列中的任务。</li>
<li><strong>shutdownNow()：</strong>试图停止所有正在执行的任务，并暂停处理等待中的任务，返回等待执行的任务列表。</li>
<li><strong>awaitTermination(long timeout, TimeUnit unit)：</strong>阻塞当前线程直到线程池中的所有任务都完成执行，或者超过了指定的时间限制。</li>
</ul>
<h2><span id="3-状态检查">3. 状态检查</span></h2><ul>
<li><strong>isShutdown()：</strong>判断线程池是否已经启动了关闭程序（调用了 shutdown() 或 shutdownNow() 方法）。</li>
<li><strong>isTerminated()：</strong>如果调用了 shutdown() 或 shutdownNow() 方法后，所有任务都已完成，则返回 true。</li>
</ul>
<h2><span id="4-其他实用方法">4. 其他实用方法</span></h2><ul>
<li><strong>getActiveCount()：</strong>返回线程池中正在积极执行任务的线程数量。</li>
<li><strong>getCompletedTaskCount()：</strong>返回已执行完毕的任务数。</li>
<li><strong>getPoolSize()：</strong>返回当前线程池中的线程数量，包括空闲线程。</li>
<li><strong>getLargestPoolSize()：</strong>返回线程池曾经创建的最大线程数量。</li>
<li><strong>getTaskCount()：</strong>估计已执行的任务总数加上仍在队列中等待执行的任务数。</li>
<li><strong>setThreadFactory(ThreadFactory threadFactory)：</strong>设置用于创建新线程的工厂。</li>
<li><strong>setRejectedExecutionHandler(RejectedExecutionHandler handler)：</strong>设置当任务无法被提交执行时使用的拒绝策略。</li>
</ul>
<h2><span id></span></h2><h1><span id="forkx2fjoin"><strong>Fork&#x2F;Join</strong></span></h1><blockquote>
<p>Fork&#x2F;Join 框架是 Java 7 引入的一个用于并行执行任务的框架，它特别适用于那些可以递归分解成更小任务的问题。这个框架旨在高效地利用多核处理器来加速计算密集型操作。以下是 Fork&#x2F;Join 框架的主要概念、工作原理以及如何使用它。</p>
</blockquote>
<h2><span id="主要概念">主要概念</span></h2><ul>
<li>Fork：将一个大任务拆分为多个子任务的过程。</li>
<li>Join：等待所有子任务完成并将它们的结果合并的过程。</li>
</ul>
<h2><span id="核心类">核心类</span></h2><ul>
<li>ForkJoinPool：执行 ForkJoinTask 的线程池。它管理着一组工作线程，并提供了一种机制来执行任务及其子任务。</li>
<li>ForkJoinTask：这是一个抽象类，代表可以在 ForkJoinPool 中执行的任务。通常情况下，你不需要直接继承这个类，而是使用它的两个具体实现之一：</li>
<li>RecursiveAction：用于没有返回结果的任务。</li>
<li>RecursiveTask<v>：用于有返回结果的任务（V 是返回值的类型）。</v></li>
</ul>
<h1><span id="aqs">AQS</span></h1><h2><span id="概念">概念</span></h2><p>全称AbstractQueuedSynchronizer（抽象队列同步器），是Java并发包（java.util.concurrent）中的一个核心组件。它提供了一个框架，用于实现依赖于先进先出（FIFO）等待队列的阻塞锁和相关的同步器（如信号量、事件等）。AQS的设计简化了开发高效且可靠的同步器的过程。</p>
<h1><span id="读写锁reentrantreadwritelock">读写锁（ReentrantReadWriteLock）</span></h1><h2><span id="基本操作">基本操作：</span></h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="type">ReentrantReadWriteLock</span> <span class="variable">rw</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReentrantReadWriteLock</span>();</span><br><span class="line"><span class="keyword">static</span> ReentrantReadWriteLock.<span class="type">ReadLock</span> <span class="variable">r</span> <span class="operator">=</span> rw.readLock();</span><br><span class="line"><span class="keyword">static</span> ReentrantReadWriteLock.<span class="type">WriteLock</span> <span class="variable">w</span> <span class="operator">=</span> rw.writeLock();</span><br></pre></td></tr></table></figure>

<p><img src="" alt="点击并拖拽以移动"></p>
<p>ReentrantReadWriteLock.ReadLock r &#x3D; rw.readLock() ： 返回用于读操作的锁</p>
<p>ReentrantReadWriteLock.WriteLock w &#x3D; rw.writeLock() : 返回用于写操作的锁</p>
<h2><span id="基本方法">基本方法</span></h2><blockquote>
<p><strong>1. 获取读锁和写锁</strong></p>
<ul>
<li>readLock() ：返回一个用于读操作的锁（Lock 对象）。</li>
<li>writeLock()：返回一个用于写操作的锁（Lock 对象）。</li>
</ul>
<p><strong>2. 锁的基本操作</strong><br> <strong>读锁（Read Lock）方法</strong></p>
<ul>
<li>void lock() ：获取读锁。如果当前没有线程持有写锁，则可以成功获取；否则会阻塞，直到写锁被释放。</li>
<li>void unlock() ：释放读锁。必须在持有读锁的线程中调用，否则会抛出llegalMonitorStateException。</li>
<li>boolean tryLock() : 尝试非阻塞地获取读锁。如果当前没有线程持有写锁，则立即获取并返回 true，否则返回 false。</li>
<li>boolean tryLock(long timeout, TimeUnit unit):尝试在指定时间内获取读锁。如果成功获取则返回 true，超时或被中断则返回 false。</li>
</ul>
<p><strong>写锁（Write Lock）方法</strong></p>
<ul>
<li>void lock():获取写锁。如果当前没有其他线程持有读锁或写锁，则可以成功获取；否则会阻塞，直到锁可用。</li>
<li>void unlock():释放写锁。必须在持有写锁的线程中调用，否则会抛出 IllegalMonitorStateException。</li>
<li>boolean tryLock():尝试非阻塞地获取写锁。如果当前没有其他线程持有读锁或写锁，则立即获取并返回 true，否则返回 false。</li>
<li>boolean tryLock(long timeout, TimeUnit unit):尝试在指定时间内获取写锁。如果成功获取则返回 true，超时或被中断则返回 false。</li>
</ul>
<p><strong>3. 公平性相关方法</strong></p>
<ul>
<li>boolean isFair():判断锁是否是公平锁。如果是公平锁，等待时间最长的线程优先获得锁；否则是非公平锁，默认为非公平模式。</li>
<li>Thread getOwner():返回当前持有写锁的线程。如果没有线程持有写锁，则返回 null。</li>
<li>int getQueueLength():返回正在等待获取写锁的线程数量。</li>
<li>Collection<thread> getQueuedThreads():返回所有正在等待获取写锁的线程集合。</thread></li>
<li>int getReadLockCount():返回当前持有读锁的线程数（包括重入次数）。</li>
<li>boolean hasQueuedThreads():判断是否有线程正在等待获取写锁。</li>
</ul>
<p><strong>4. 状态检查方法</strong></p>
<ul>
<li>boolean isWriteLocked():判断写锁是否被任何线程持有。</li>
<li>boolean isWriteLockedByCurrentThread():判断当前线程是否持有写锁。</li>
<li>int getWriteHoldCount():返回当前线程持有写锁的重入次数。如果当前线程未持有写锁，则返回 0。</li>
<li>int getReadHoldCount()返回当前线程持有读锁的重入次数。如果当前线程未持有读锁，则返回 0。</li>
</ul>
<p><strong>5. 条件变量（Condition）支持</strong><br> 虽然 ReentrantReadWriteLock 支持条件变量，但需要注意：</p>
<ul>
<li>读锁不支持条件变量：尝试使用读锁创建条件变量会导致 UnsupportedOperationException。</li>
<li>写锁支持条件变量：可以使用写锁创建条件变量。</li>
</ul>
</blockquote>
<h2><span id="读读锁可以并发">读读锁可以并发</span></h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="type">ReentrantReadWriteLock</span> <span class="variable">rw</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReentrantReadWriteLock</span>();</span><br><span class="line"><span class="keyword">static</span> ReentrantReadWriteLock.<span class="type">ReadLock</span> <span class="variable">r</span> <span class="operator">=</span> rw.readLock();</span><br><span class="line"><span class="keyword">static</span> ReentrantReadWriteLock.<span class="type">WriteLock</span> <span class="variable">w</span> <span class="operator">=</span> rw.writeLock();</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">read</span><span class="params">()</span> &#123;</span><br><span class="line">    r.lock();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;获取read锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">        sleep(<span class="number">1000</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;释放read锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">        r.unlock();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">write</span><span class="params">()</span> &#123;</span><br><span class="line">    w.lock();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;获取write锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">        sleep(<span class="number">1000</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        log.debug(<span class="string">&quot;释放write锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">        w.unlock();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Thread</span>(Test5::read, <span class="string">&quot;t1&quot;</span>).start();</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Thread</span>(Test5::read, <span class="string">&quot;t2&quot;</span>).start();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="" alt="点击并拖拽以移动"></p>
<p><img src="/./../images/b8212d2086344f0b9a130e52d2ed6b31.png" alt="img"><img src="" alt="点击并拖拽以移动">  </p>
<h2><span id="读写锁互相阻塞">读写锁互相阻塞</span></h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="type">ReentrantReadWriteLock</span> <span class="variable">rw</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReentrantReadWriteLock</span>();</span><br><span class="line">   <span class="keyword">static</span> ReentrantReadWriteLock.<span class="type">ReadLock</span> <span class="variable">r</span> <span class="operator">=</span> rw.readLock();</span><br><span class="line">   <span class="keyword">static</span> ReentrantReadWriteLock.<span class="type">WriteLock</span> <span class="variable">w</span> <span class="operator">=</span> rw.writeLock();</span><br><span class="line"></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">read</span><span class="params">()</span> &#123;</span><br><span class="line">       r.lock();</span><br><span class="line">       <span class="keyword">try</span> &#123;</span><br><span class="line">           log.debug(<span class="string">&quot;获取read锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">           sleep(<span class="number">1000</span>);</span><br><span class="line">       &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">           e.printStackTrace();</span><br><span class="line">       &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">           log.debug(<span class="string">&quot;释放read锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">           r.unlock();</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">write</span><span class="params">()</span> &#123;</span><br><span class="line">       w.lock();</span><br><span class="line">       <span class="keyword">try</span> &#123;</span><br><span class="line">           log.debug(<span class="string">&quot;获取write锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">           sleep(<span class="number">1000</span>);</span><br><span class="line">       &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">           e.printStackTrace();</span><br><span class="line">       &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">           log.debug(<span class="string">&quot;释放write锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">           w.unlock();</span><br><span class="line">       &#125;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"></span><br><span class="line">       <span class="keyword">new</span> <span class="title class_">Thread</span>(Test5::read, <span class="string">&quot;t1&quot;</span>).start();</span><br><span class="line">       <span class="keyword">new</span> <span class="title class_">Thread</span>(Test5::write, <span class="string">&quot;t2&quot;</span>).start();</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>

<p><img src="" alt="点击并拖拽以移动"></p>
<p> <img src="/./../images/5370b820c3e94ab1a36b63396859080a.png" alt="img"><img src="" alt="点击并拖拽以移动"> </p>
<h2><span id="写写锁互相阻塞">写写锁互相阻塞</span></h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="type">ReentrantReadWriteLock</span> <span class="variable">rw</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReentrantReadWriteLock</span>();</span><br><span class="line"> <span class="keyword">static</span> ReentrantReadWriteLock.<span class="type">ReadLock</span> <span class="variable">r</span> <span class="operator">=</span> rw.readLock();</span><br><span class="line"> <span class="keyword">static</span> ReentrantReadWriteLock.<span class="type">WriteLock</span> <span class="variable">w</span> <span class="operator">=</span> rw.writeLock();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">read</span><span class="params">()</span> &#123;</span><br><span class="line">     r.lock();</span><br><span class="line">     <span class="keyword">try</span> &#123;</span><br><span class="line">         log.debug(<span class="string">&quot;获取read锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">         sleep(<span class="number">1000</span>);</span><br><span class="line">     &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">         e.printStackTrace();</span><br><span class="line">     &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">         log.debug(<span class="string">&quot;释放read锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">         r.unlock();</span><br><span class="line">     &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">write</span><span class="params">()</span> &#123;</span><br><span class="line">     w.lock();</span><br><span class="line">     <span class="keyword">try</span> &#123;</span><br><span class="line">         log.debug(<span class="string">&quot;获取write锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">         sleep(<span class="number">1000</span>);</span><br><span class="line">     &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">         e.printStackTrace();</span><br><span class="line">     &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">         log.debug(<span class="string">&quot;释放write锁, &#123;&#125;&quot;</span>, System.currentTimeMillis());</span><br><span class="line">         w.unlock();</span><br><span class="line">     &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line"></span><br><span class="line">     <span class="keyword">new</span> <span class="title class_">Thread</span>(Test5::write, <span class="string">&quot;t1&quot;</span>).start();</span><br><span class="line">     <span class="keyword">new</span> <span class="title class_">Thread</span>(Test5::write, <span class="string">&quot;t2&quot;</span>).start();</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<p><img src="" alt="点击并拖拽以移动"></p>
<p> <img src="/./../images/9c688fcb36f640cfaa9a05156b968dd5.png" alt="img"><img src="" alt="点击并拖拽以移动"> </p>
<p>写锁是独占的，读锁是共享的。</p>
<hr>
<p><strong>如有错误，欢迎指正！！！</strong></p>
<p>碎碎念：Java并发编程JUC篇，目前来说是个基础篇，更深入的都还没学，后续有时间会进一步完善qwq，juc内容很多，如果想要深入学习，还是要看一下源码深入理解一下底层原理。。。</p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta"><i class="fas fa-circle-user fa-fw"></i>文章作者: </span><span class="post-copyright-info"><a href="http://xuanskeys.github.io">xuanskeys</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta"><i class="fas fa-square-arrow-up-right fa-fw"></i>文章链接: </span><span class="post-copyright-info"><a href="http://xuanskeys.github.io/2025/04/20/JUC4/">http://xuanskeys.github.io/2025/04/20/JUC4/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta"><i class="fas fa-circle-exclamation fa-fw"></i>版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来源 <a href="http://xuanskeys.github.io" target="_blank">XuanCode</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/1/">1</a></div><div class="post-share"><div class="social-share" data-image="/image/person.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><a class="pagination-related" href="/2025/04/20/JUC3/" title="Java并发编程3(CAS)"><div class="cover" style="background: var(--default-bg-color)"></div><div class="info"><div class="info-1"><div class="info-item-1">上一篇</div><div class="info-item-2">Java并发编程3(CAS)</div></div><div class="info-2"><div class="info-item-1">Java内存模型(JMM)概念百度百科：java内存模型_百度百科  Java内存模型（Java Memory Model,...</div></div></div></a><a class="pagination-related" href="/2025/04/20/%E5%9F%BA%E7%A1%80%E7%AE%97%E6%B3%95/" title="基础算法"><div class="cover" style="background: var(--default-bg-color)"></div><div class="info text-right"><div class="info-1"><div class="info-item-1">下一篇</div><div class="info-item-2">基础算法</div></div><div class="info-2"><div class="info-item-1">快速排序图解分析：  模板：12345678910111213141516171819202122//核心思想：分而治之//函数参数：(需要处理的数组， 数组的左边界， 数组的右边界)//函数：使得左边小于x, 右边大于x void quick_sort(int q[], int l, int r)&#123;    //递归出口    if (l &gt;= r) return;        //运用双指针，左指针指向的数小于x, 右指针指向的数大于x    int x = (q[l] + q[r]) / 2;    int i = l - 1, j = r + 1;    while (i &lt; j)    &#123;        do i ++; while(q[i] &lt; x);        do j --; while(q[j] &gt; x);        if (i &lt; j) swap(q[i], q[j]);    &#125;        //递归处理左右子区间    quick_sort(q, l, j);   ...</div></div></div></a></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><a class="pagination-related" href="/2025/04/20/JUC1/" title="JUC并发编程1(初识进程和线程)"><div class="cover" style="background: var(--default-bg-color)"></div><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2025-04-20</div><div class="info-item-2">JUC并发编程1(初识进程和线程)</div></div><div class="info-2"><div class="info-item-1"> 初识进程和线程初识进程：定义：  进程（Process）是计算机中的程序关于某数据集合上的一次运行活动，是系统进行资源分配的基本单位，是操作系统结构的基础。在早期面向进程设计的计算机结构中，进程是程序的基本执行实体；在当代面向线程设计的计算机结构中，进程是线程的容器。程序是指令、数据及其组织形式的描述，进程是程序的实体。（百度百科） 进程由程序、数据和进程控制块三部分组成。   什么是进程？ 狭义定义：进程是正在运行的程序的实例。 广义定义：进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元，在传统的操作系统中，进程既是基本的分配单元，也是基本的执行单元。   eg：进程可以看做是程序的实例，你可以打开多个程序，每一个程序就是一个进程（比如你重复打开QQ登录不同的用户，每一个用户登录的那个程序就是一个进程）。   如果你关闭一个窗口，那么这个进程也就结束了  概念：1.进程是一个实体。 ...</div></div></div></a><a class="pagination-related" href="/2025/04/20/JUC2/" title="Java并发编程2(锁-Sychronized)"><div class="cover" style="background: var(--default-bg-color)"></div><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2025-04-20</div><div class="info-item-2">Java并发编程2(锁-Sychronized)</div></div><div class="info-2"><div class="info-item-1">认识Java对象头  32位虚拟机对象头：   64位虚拟机对象头：     1.Mark Word（标记字）:  Mark Word是对象头的一部分，用于存储对象自身的哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID（或偏向时间戳）、偏向模式以及锁的状态等信息。 标记字的大小和具体内容可能因JVM实现的不同而有所变化。例如，在64位JVM上，默认情况下Mark Word占用64位（8字节），而在32位JVM上则是32位（4字节）。  2.Class Pointer（类指针）:  这是指向该对象对应类（Class）的指针，通过这个指针可以访问到对象所属类的元数据（如方法表、字段描述等）。类指针的大小依赖于JVM的具体实现及其是否开启了压缩指针（Compressed Oop）选项。 在某些情况下，比如当使用了-XX:+UseCompressedClassPointers选项时，类指针会被压缩以节省内存。  3.Array...</div></div></div></a><a class="pagination-related" href="/2025/04/20/JUC3/" title="Java并发编程3(CAS)"><div class="cover" style="background: var(--default-bg-color)"></div><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2025-04-20</div><div class="info-item-2">Java并发编程3(CAS)</div></div><div class="info-2"><div class="info-item-1">Java内存模型(JMM)概念百度百科：java内存模型_百度百科  Java内存模型（Java Memory Model,...</div></div></div></a><a class="pagination-related" href="/2025/04/20/Java%E8%99%9A%E6%8B%9F%E6%9C%BA/" title="Java虚拟机"><div class="cover" style="background: var(--default-bg-color)"></div><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2025-04-20</div><div class="info-item-2">Java虚拟机</div></div><div class="info-2"><div class="info-item-1">JVM的概念百度百科：java虚拟机 什么是虚拟机？虚拟机是一种抽象化的计算机，通过在实际的计算机上仿真模拟各种计算机功能来实现的。 为什么要有JVM？  Java设计的初衷是使要建的能在任何平台上运行的程序不需要再在每个单独的平台上由程序员进行重写或重编译。 Java虚拟机使这个愿望变为可能，因为它能知道每条指令的长度和平台的其他特性。 JVM的设计目标是提供一个基于抽象规格描述的计算机模型，为解释程序开发人员提供的任何系统上运行。   什么是java虚拟机?JVM全称Java Virtual...</div></div></div></a><a class="pagination-related" href="/2025/04/20/Java%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B/" title="Java面向对象编程"><div class="cover" style="background: var(--default-bg-color)"></div><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2025-04-20</div><div class="info-item-2">Java面向对象编程</div></div><div class="info-2"><div class="info-item-1">什么是面向对象编程(OOP)? 它将数据和相关操作封装在对象中，通过对象之间的交互来解决问题。 简单来说，就是世界上所有的物品，都可以是一个对象，对象是一种特殊的数据结构，里面存储物品的相关属性信息，类似于一张表结构。 类就相当于对象的一个模版，结构相同的对象可以使用同一个类来构造   JVM虚拟机JVM是什么? JVM（Java虚拟机）并不是直接安装在操作系统上的一个单独的实体或文件夹，而是一种抽象的计算模型，它通常是由一个程序或者软件包的一部分来实现的。当你在计算机上安装Java运行环境（例如，Java Development Kit, JDK 或者 Java Runtime Environment, JRE）时，实际上就包含了JVM的实现 当你运行一个Java程序时，比如通过命令行输入java...</div></div></div></a><a class="pagination-related" href="/2025/04/20/Oracle/" title="Oracle基本语法"><div class="cover" style="background: var(--default-bg-color)"></div><div class="info text-center"><div class="info-1"><div class="info-item-1"><i class="far fa-calendar-alt fa-fw"></i> 2025-04-20</div><div class="info-item-2">Oracle基本语法</div></div><div class="info-2"><div class="info-item-1">前言： 1.使用的数据库不同，所使用的语法也略有不同 2.SQL对大小写不敏感 3.Oracle中对引号里面的内容大小写敏感 3.表空间名、文件路径……等需要用单引号将其包含 4.一般引号里面的内容需要大写   准备工作：安装tips：PLSQL、Oracle以及客户端远程连接服务器笔记（仅供参考）-CSDN博客  （1）.Win+R打开services.msc     （2）启动一些服务： （qwq我不知道哪些有用，哪些没用，所以我都把打开了，不知道有没有负面影响，大家参考一下别的博客吧）     登录：1.打开SQL Plus命令行工具第一种方式：  第二种方式： （1）win+R 打开cmd   （2）输入sqlplus    2.以不同用户登录 注意： 1.使用用户口令这种形式登录的时候，是不显示密码的，口令输入的时候是不显示的，直接输就好 2.若是想以显示密码的形式输入，直接在用户名那一块输入：用户名&#x2F;密码 3.超级管理员（sys）输入时需要注意指定 as sysdba  SYSTEM（普通管理员）：...</div></div></div></a></div></div><hr class="custom-hr"/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div id="gitalk-container"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info text-center"><div class="avatar-img"><img src="/image/person.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info-name">xuanskeys</div><div class="author-info-description"></div><div class="site-data"><a href="/archives/"><div class="headline">文章</div><div class="length-num">10</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">1</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">5</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/xuanskeys"><i class="fab fa-github"></i><span>Follow Me</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">欢迎来到XuanCode。更多详细信息请前往CSDN：https://blog.csdn.net/m0_73569492?type=blog</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">1.</span> <span class="toc-text">原子变量</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">1.1.</span> <span class="toc-text">  基本类型原子变量</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">1.2.</span> <span class="toc-text">对象引用原子变量</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">1.3.</span> <span class="toc-text">数组类型的原子变量</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">1.4.</span> <span class="toc-text">字段更新器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">1.5.</span> <span class="toc-text">AtomicStampedReference</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">1.5.1.</span> <span class="toc-text">介绍：</span></a></li><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">1.5.2.</span> <span class="toc-text">ABA问题的描述</span></a></li><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">1.5.3.</span> <span class="toc-text">ABA问题的具体场景</span></a></li><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">1.5.4.</span> <span class="toc-text">源码分析</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">1.5.4.1.</span> <span class="toc-text">构造方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">1.5.4.2.</span> <span class="toc-text">compareAndSet</span></a></li><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">1.5.4.3.</span> <span class="toc-text">weakCompareAndSet</span></a></li><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">1.5.4.4.</span> <span class="toc-text">attemptStamp</span></a></li><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">1.5.4.5.</span> <span class="toc-text">Unsafe机制</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">2.</span> <span class="toc-text">并发集合</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">2.1.</span> <span class="toc-text">集合</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">2.2.</span> <span class="toc-text">ConcurrentHashMap</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">2.2.1.</span> <span class="toc-text">特点</span></a></li><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">2.2.2.</span> <span class="toc-text">扩容机制</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">2.2.2.1.</span> <span class="toc-text">触发条件：</span></a></li><li class="toc-item toc-level-4"><a class="toc-link"><span class="toc-number">2.2.2.2.</span> <span class="toc-text">扩容过程</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">3.</span> <span class="toc-text">Executor框架</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">3.1.</span> <span class="toc-text">Executor框架主要组成</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">3.2.</span> <span class="toc-text">线程池</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">3.2.1.</span> <span class="toc-text">概念</span></a></li><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">3.2.2.</span> <span class="toc-text">线程池的创建</span></a></li><li class="toc-item toc-level-3"><a class="toc-link"><span class="toc-number">3.2.3.</span> <span class="toc-text">线程池工作流程</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">3.3.</span> <span class="toc-text"></span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">4.</span> <span class="toc-text">ThreadPoolExecutor</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">4.1.</span> <span class="toc-text">案例引入：</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">4.2.</span> <span class="toc-text">参数说明：</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">4.3.</span> <span class="toc-text">1. 提交任务</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">4.4.</span> <span class="toc-text">2. 线程池管理</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">4.5.</span> <span class="toc-text">3. 状态检查</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">4.6.</span> <span class="toc-text">4. 其他实用方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">4.7.</span> <span class="toc-text"></span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">5.</span> <span class="toc-text">Fork&#x2F;Join</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">5.1.</span> <span class="toc-text">主要概念</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">5.2.</span> <span class="toc-text">核心类</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">6.</span> <span class="toc-text">AQS</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">6.1.</span> <span class="toc-text">概念</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-number">7.</span> <span class="toc-text">读写锁（ReentrantReadWriteLock）</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">7.1.</span> <span class="toc-text">基本操作：</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">7.2.</span> <span class="toc-text">基本方法</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">7.3.</span> <span class="toc-text">读读锁可以并发</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">7.4.</span> <span class="toc-text">读写锁互相阻塞</span></a></li><li class="toc-item toc-level-2"><a class="toc-link"><span class="toc-number">7.5.</span> <span class="toc-text">写写锁互相阻塞</span></a></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2025/04/20/%E6%9C%80%E7%9F%AD%E8%B7%AF%E9%97%AE%E9%A2%98/" title="最短路问题">最短路问题</a><time datetime="2025-04-20T02:09:44.000Z" title="发表于 2025-04-20 10:09:44">2025-04-20</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2025/04/20/Java%E8%99%9A%E6%8B%9F%E6%9C%BA/" title="Java虚拟机">Java虚拟机</a><time datetime="2025-04-20T02:07:29.000Z" title="发表于 2025-04-20 10:07:29">2025-04-20</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2025/04/20/%E5%9F%BA%E7%A1%80%E7%AE%97%E6%B3%95/" title="基础算法">基础算法</a><time datetime="2025-04-20T02:03:22.000Z" title="发表于 2025-04-20 10:03:22">2025-04-20</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2025/04/20/JUC4/" title="Java并发编程4（JUC篇）">Java并发编程4（JUC篇）</a><time datetime="2025-04-20T02:01:01.000Z" title="发表于 2025-04-20 10:01:01">2025-04-20</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2025/04/20/JUC3/" title="Java并发编程3(CAS)">Java并发编程3(CAS)</a><time datetime="2025-04-20T01:59:28.000Z" title="发表于 2025-04-20 09:59:28">2025-04-20</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2025 By xuanskeys</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo 7.3.0</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly 5.3.5</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="日间和夜间模式切换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="前往评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><div class="js-pjax"><script>(() => {
  const isShuoshuo = GLOBAL_CONFIG_SITE.pageType === 'shuoshuo'
  const option = null

  const commentCount = n => {
    const isCommentCount = document.querySelector('#post-meta .gitalk-comment-count')
    if (isCommentCount) {
      isCommentCount.textContent= n
    }
  }

  const initGitalk = (el, path) => {
    if (isShuoshuo) {
      window.shuoshuoComment.destroyGitalk = () => {
        if (el.children.length) {
          el.innerHTML = ''
          el.classList.add('no-comment')
        }
      }
    }

    const gitalk = new Gitalk({
      clientID: '',
      clientSecret: '',
      repo: 'xuanskeys.github.io',
      owner: 'xuanskeys',
      admin: ['xuanskeys'],
      updateCountCallback: commentCount,
      ...option,
      id: isShuoshuo ? path : (option && option.id) || '76f21023995332283400013b1299adb6'
    })

    gitalk.render('gitalk-container')
  }

  const loadGitalk = async(el, path) => {
    if (typeof Gitalk === 'function') initGitalk(el, path)
    else {
      await btf.getCSS('https://cdn.jsdelivr.net/npm/gitalk/dist/gitalk.min.css')
      await btf.getScript('https://cdn.jsdelivr.net/npm/gitalk/dist/gitalk.min.js')
      initGitalk(el, path)
    }
  }

  if (isShuoshuo) {
    'Gitalk' === 'Gitalk'
      ? window.shuoshuoComment = { loadComment: loadGitalk }
      : window.loadOtherComment = loadGitalk
    return
  }

  if ('Gitalk' === 'Gitalk' || !false) {
    if (false) btf.loadComment(document.getElementById('gitalk-container'), loadGitalk)
    else loadGitalk()
  } else {
    window.loadOtherComment = loadGitalk
  }
})()</script></div><script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/gh/xiabo2/CDN@latest/fishes.js"></script><script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-nest.min.js"></script><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/click-heart.min.js" async="async" mobile="false"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="text-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></div></body></html>